#include "ClientPolling.h"


typedef std::map<std::string, std::string> MapFiles;
typedef std::vector<std::string> NamesFiles;

ClientPolling::ClientPolling(Socket *s, Mutex* m,int time_interval,
		std::string& index_path, std::string& storage_path,std::string user, std::string pass) {
	std::string userFolder(getenv("HOME"));
	this->sock = s;
	this->m = m;
	this->storage_path =storage_path;
	this->time_interval = time_interval;
	this->index_path = index_path;
	this->user=user;
	this->pass=pass;
}

std::pair<MapFiles,NamesFiles> ClientPolling::process(std::vector<std::string>& file_names) {
	NamesFiles::iterator i = file_names.begin();
	MapFiles files_to_send;
	std::vector <std::string> files_to_delete;
	m->lock();
	Index indice(&index_path);
	indice.LoadFromDisk();
	MapFiles mapFiles = indice.GetMappedIndex();
	MapFiles::iterator j;
	for (NamesFiles::iterator endi = file_names.end(); endi != i;i++) {
		std::string name_file_handler = *i;
		std::string path_file_name = storage_path + "/" + name_file_handler;

		std::string binary_file = HexEncode::FileToString(path_file_name.c_str());
		std::string hash = md5(binary_file); //calcula hash

		bool to_send = true; // Novedad, hay que enviar al server
		bool file_exist=false; // El archivo existe, pero fue modificado
		j = mapFiles.begin();
		for (MapFiles::iterator endj = mapFiles.end();
				endj != j; j++) {
			std::string name_file_index = j->first;
			if ((name_file_handler == name_file_index)
					and (hash == j->second)) {
				to_send = false;
				break;
			}
			else if((name_file_handler == name_file_index)
					and (hash != j->second)){
				file_exist = true;
				break;
			}

		}
		if (to_send) {
			files_to_send.insert(std::pair<std::string, std::string>(name_file_handler,
							hash));
			//Agrego al indice
			indice.AddKey(&name_file_handler,&hash);
		}
		if(file_exist){
			indice.EditKey(&name_file_handler,&hash);
		}
	}

	//Me fijo cuales hay q eliminar
	j =mapFiles.begin();
	for (MapFiles::iterator endj = mapFiles.end(); endj != j;j++){
		bool to_delete = true;
		std::string name_file = j->first;
		i = file_names.begin();

		for (NamesFiles::iterator endi = file_names.end(); endi != i;i++) {
			if(name_file == *i){
				to_delete=false;
				break;
			}
		}
		if (to_delete){
			files_to_delete.push_back(name_file);
			indice.DeleteKey(&name_file);
		}
	}


	//Actualizo indice en el archivo
    indice.SaveToDisk();

	m->unlock();
	std::pair<MapFiles,NamesFiles> pair_update(files_to_send,files_to_delete);
	return pair_update;
}


void ClientPolling::send_news(MapFiles& news) {
	MapFiles::iterator i = news.begin();
	m->lock();
	for (MapFiles::iterator endi = news.end();endi != i; i++) {
		std::string name = i->first;
		std::string path_name=storage_path+"/"+name;
		std::string hash = i->second;
		HexEncode he(path_name.c_str());
		std::string hexa = he.Encode(); // pasa a hexa el archivo
		PutFile *pf = new PutFile(&name, &hash, &hexa,this->user,this->pass);
		sock->Send(pf);
		category.info("Sending "+name+ " ...");
		delete pf;

	}
	m->unlock();
}

void ClientPolling::delete_olds(NamesFiles& old_to_delete){
	NamesFiles::iterator i = old_to_delete.begin();
    for(NamesFiles::iterator endi = old_to_delete.end(); endi != i; i++){
    	std::string name=*i;
    	category.info("To deleting "+name);
    	Delete *d = new Delete(&name,this->user,this->pass);
        sock->Send(d);
		delete d;
    }
}
void ClientPolling::run() {
	sleep(time_interval); //Espero un tiempo para que primero sincronize con el server
	directoryHandler handler(&this->storage_path);
	while (r) {
		category.notice("New Polling...");
		NamesFiles file_names = handler.getFilesNames();
		std::pair<MapFiles,NamesFiles> pair_update = this->process(file_names);

		MapFiles news = pair_update.first;
        NamesFiles old_to_delete = pair_update.second;

        this->send_news(news);
		this->delete_olds(old_to_delete);
		sleep(time_interval);

	}

}
ClientPolling::~ClientPolling() {
}

